// 有一个二维矩阵 A 其中每个元素的值为 0 或 1 。
// 移动是指选择任一行或列，并转换该行或列中的每一个值：将所有 0 都更改为 1，将所有 1 都更改为 0。
// 在做出任意次数的移动后，将该矩阵的每一行都按照二进制数来解释，矩阵的得分就是这些数字的总和。
// 返回尽可能高的分数。

// 暴露接口
const matrixScore = function (A: number[][]):number{
    // 安全校验
    if (A.length < 1) {
        return 0;
    }
    let res: number = 0; // 结果变量
    // 先保证第一列全部为1
    for (let i = 0; i < A.length; i++) {
        // 目前扫描到第i行1第一列
        if (A[i][0] === 0) {
            matrixScore_rowReverse(A, i);
        }
    }
    // 现在已经保证第一行全部为一，然后需要保证后面每列除第一个位置的1外尽可能多
    for (let i = 0; i < A[0].length; i++) {
        let oneCount: number = 0;
        for (let j = 0; j < A.length; j++) {
            if (A[j][i] === 1) oneCount++;
        }
        // 如果这一列的1比较少那就翻转这列--->为了追求时间复杂度其实也可以不用翻转矩阵
        if (oneCount < A.length - oneCount) {
            matrixScore_colReverse(A, i);
        }
        // 翻转完开始计算总和
        res += Math.max(oneCount, A.length - oneCount) * (1 << (A[0].length - i - 1));
    }
    return res;
};
// 列反转
function matrixScore_colReverse(matrix: number[][], col: number) {
    for (let i = 0; i < matrix.length; i++) {
        matrix[i][col] = matrix[i][col] === 1 ? 0 : 1;
    }
}
// 行反转
function matrixScore_rowReverse(matrix: number[][], row: number) {
    if (matrix.length < 1) {
        return matrix;
    }
    for (let i = 0; i < matrix[0].length; i++) {
        matrix[row][i] = matrix[row][i] === 1 ? 0 : 1;
    }
}


matrixScore([
    [0, 0, 1, 1],
    [1, 0, 1, 0],
    [1, 1, 0, 0]
])


// 这道题实际上还是比较唬人的一道题目，看上去翻转规则复杂，其实想通了就比较容易
// 最重要的是想通一点，那就是我们所求的是最后的结果，实际上不关心翻转的操作如何
// 翻译一下题目想要的结果：给定二维数组（只含0，1），任意翻转某些行/列，使得矩阵每行表示的十进制数的和最大。
// 题目要求每行表示的数的和最大，那么我们很容易就想到可以让每行表示的数尽可能的大。
// 又因为每行实际上只含0和1，所以我们肯定尽可能地希望每行的第一个元素是1，毕竟数位大
// 而这一定是可以做到的！因为如果第一行的数为 0，我们可以这行基于行进行反转得到1
// 这一轮操作过后我们已经可以满足到每一行的第一个位置元素为1
// 之后我们想让这个数组的剩余部分也同样尽可能大，我们基于列来扫描这个矩阵
// 对于每列（从高位到低位顺序），我们肯定希望 1 越多越好，因为每个 1 都会让那行的数字更大。
// 而规则也很简单，统计每列中 0 和 1 的个数，如果 0 多就基于列翻转，否则不进行基于列翻转
// 这两番操作结束后也就得到了最后的结果。